package compiler_rt;

import java.util.HashMap;

/**
 * The fixed part of the interpreter. The class for closures.
 * 
 * Closures serve for storing the association between names and values at
 * runtime, as well as function code.
 */
public class Closure extends HashMap<String, Closure> implements Cloneable {
	private static final long serialVersionUID = 7268709053951041352L;
	@SuppressWarnings("serial")
	public static final Closure IDENT = new Closure(null, null){
		public Closure app(Closure param) {
			return param;
		};
	};
	private Closure parent = null;
	private String paramName = null;
	
	
	public Closure(Closure parent, String paramName) {
		super(2);
		this.parent = parent;
		this.paramName = paramName;
	}

	private void bind(String s, Closure c) {
		put(s, c);
	}

	public Closure bindSelf(String fnName) {
		put(fnName, this);
		return this;
	}

	/*
	 * Find the value of a variable in the environment. Could have used 
	 * deBrujin numbering to compute the depth of a variable statically.  
	 */
	public Closure lookupEnv(String s) {
		Closure e = get(s);
		if (e == null) {
			/* lookup the variable in the parent scope recursively */
			e = parent.lookupEnv(s);
		}
		return e;
	}

	/* apply the function-closure to an actual argument */
	public Closure app(Closure param) {
		/* Create an activation record with the new parameter */
		Closure activation = (Closure) this.activate();
		activation.bind(paramName, param);

		/* ... and calls the closure */
		return activation.body();
	}

	/* should be implemented by any function */
	public Closure body() {
		throw new RuntimeException("Non-function expression cannot be applied");
	}

	/* returns an activation record based on the current closure */
	public Closure activate() {
		return (Closure) this.clone();
	}
}
